<?php
if (!defined('GOOGLEAPILIB')) {
	define('GOOGLEAPILIB', dirname(__FILE__).'/google-api-php-client-master/src');
	set_include_path(get_include_path().PATH_SEPARATOR.GOOGLEAPILIB);
}
require_once 'Google/Client.php';
require_once 'Google/Service/Calendar.php';
require_once dirname(__FILE__) . '/../DateMath.php';
$Google_Client;

class Google_Calender
{
	const KEY_ACCESS_TOKEN = 'ACCESS_TOKEN';
	const KEY_Google認証URL = 'goa';
	const KEY_認証後に表示するURL ='bkurl';
	const 踏み台ページURL = 'http://minder.minibird.jp/hariushigauth.php';
	const TYPE_TOKEN = 'token';
	const TYPE_ACCESS_TOKEN = 'accesstoken';

	/**
	 * アクセストークンをセッションに作成する
	 * @param string $applicationUrl
	 */
	static public function initSession($applicationUrl)
	{
		if (!empty($_REQUEST['code'])) {
			self::createCalendarClient($_REQUEST['code']);
		} else {
			if (!self::AccessTokenExists()) {
				self::getAccessTokenFromGoogleSite($applicationUrl);
			} else {
				self::createCalendarClient($_SESSION[self::KEY_ACCESS_TOKEN], self::TYPE_ACCESS_TOKEN);
			}
		}
	}

	static public function createCalendarClient($code, $tokenType = self::TYPE_TOKEN)
	{
		if (!isset($_SESSION)) {
			session_start();
		}
		GLOBAL $Google_Client;
		if (($Google_Client instanceof Google_Client) !== TRUE) {
			$Google_Client = new Google_Client();
			$Google_Client->setClientId(self::CLIENT_ID);
			$Google_Client->setClientSecret(self::CLIENT_SECRET);
			$Google_Client->setRedirectUri(self::REDIRECT_URI);
			$Google_Client->setDeveloperKey(self::DEVELOPER_KEY);
			$Google_Client->addScope(Google_Service_Calendar::CALENDAR);
		}
		switch ($tokenType) {
			case self::TYPE_TOKEN:
				$Google_Client->authenticate($code);
				$_SESSION[self::KEY_ACCESS_TOKEN] = $Google_Client->getAccessToken();
				break;
			case self::TYPE_ACCESS_TOKEN:
				$Google_Client->setAccessToken($code);
		}
	}

	static public function AccessTokenExists()
	{
		if (!isset($_SESSION)) {
			session_start();
		}
		if (!isset($_SESSION[self::KEY_ACCESS_TOKEN])) {
			return FALSE;
		}
		$token= json_decode($_SESSION[self::KEY_ACCESS_TOKEN]);
		if ($token === NULL) {
			return FALSE;
		}
		$now = time();
		if($now - 60  > $token->created + $token->expires_in) {
			return FALSE;
		}
		return TRUE;
	}

	static public function getAccessTokenFromGoogleSite($認証後に表示するURL)
	{
		$Client = new Google_Client();
		$Client->setClientId(self::CLIENT_ID);
		$Client->setClientSecret(self::CLIENT_SECRET);
		$Client->setRedirectUri(self::REDIRECT_URI);
		$Client->setDeveloperKey(self::DEVELOPER_KEY);
		$Client->addScope(Google_Service_Calendar::CALENDAR);
		$Google認証URL = urlencode($Client->createAuthUrl());
		$認証後に表示するURL = urlencode($認証後に表示するURL);
		header("Location: " . self::踏み台ページURL . "?".self::KEY_認証後に表示するURL."={$認証後に表示するURL}" . "&" . self::KEY_Google認証URL . "={$Google認証URL}");
		exit();
		return;
	}

	/**
	 * 開始日時と終了日時（UNIXタイムスタンプ）から所要時間（分）を返す
	 * @param unknown $startUDate
	 * @param unknown $endUDate
	 * @return number
	 */
	public static function getTimeLength($startUDate, $endUDate)
	{
		$resultMinutes = 0;
		$uLength = $endUDate - $startUDate;
		$minutes = $uLength / 60;
		$resultMinutes = round($minutes);
		return $resultMinutes;
	}
	/**
	 * UNIXタイムスタンプからイベント開始終了日時文字列を返す
	 * 2013-11-24 20:00
	 * @param unknown $uTime
	 * @param string $allDayFlg
	 */
	public static function uTime2String($uTime, $allDayFlg=FALSE)
	{
		$sResult = date('Y-m-d', $uTime);
		if ($allDayFlg == FALSE) {
			$sResult .= ' ' . date('H:i', $uTime);
		}
		return $sResult;
	}

	const CLIENT_ID ='266200625647-05hfpdbklavmq9cspu3vvg4pnu2sqdda.apps.googleusercontent.com';
	const CLIENT_SECRET = 'Ly2VDHfid5lsuWN4cF16xwM1';
	const REDIRECT_URI='http://minder.minibird.jp/hariushigauth.php';
	const DEVELOPER_KEY = 'AIzaSyAMIC-A-VoOVSadE62bnD-l-zs289Vl0hQ';

	public $状態 = TRUE;
	protected $_カレンダーサービス;
	protected $_カレンダーリスト;
	protected $_選択カレンダーＩＤ;
	protected $_検索結果イベント数;

	public function __construct()
	{
		GLOBAL $Google_Client;
		if (($Google_Client instanceof Google_Client) !== TRUE) {
			$this->状態 = FALSE;
			return;
		}
		$カレンダーサービス = new Google_Service_Calendar($Google_Client);
		$this->_カレンダーサービス = $カレンダーサービス;
		$this->_カレンダーリスト = $this->_カレンダーサービス->calendarList->listCalendarList();
	}

	public function カレンダー一覧を返す()
	{
		return $this->getCalendarList();
	}
	/**
	 * カレンダーリストオブジェクトを返す
	 * @return boolean|Google_Service_Calendar_CalendarList
	 */
	public function getCalendarList()
	{
		if (!$this->状態){return FALSE;}
		return $this->_カレンダーリスト;
	}

	public function 登録カレンダー数を返す()
	{
		return $this->getCalendarCount();
	}
	/**
	 * 登録カレンダー数を返す
	 * @return number
	 */
	public function getCalendarCount()
	{
		return $this->_カレンダーリスト->count();
	}

	const KEY_EVENT_ID = 'ID';
	const KEY_EVENT_NAME = 'NAME';
	const KEY_EVENT_START_TIME = 'START_TIME';
	const KEY_EVENT_END_TIME = 'END_TIME';
	const KEY_EVENT_ALLDAY = 'ALLDAY';
	const KEY_EVENT_UPDATED = 'UPDATED';
	const KEY_EVENT_CONTENT = 'CONTENT';
	public function イベント一覧を返す($updatedMin)
	{
		return $this->getEventList($updatedMin);
	}
	/**
	 * イベント一覧を返す
	 * @param $updatedMin 更新日 '2013-11-23T04:09:14'
	 * @return Google_Service_Calendar_Events
	 */
	public function getEventList($updatedMin)
	{
		$result = array();
		$updatedMin = date('Y-m-d\TH:i:s+0900', strtotime($updatedMin));
		$farLimit = strtotime('2014-11-24T00:00:00Z') - strtotime('2014-10-28T00:00:00Z');
		if (time() - strtotime($updatedMin) > $farLimit) {
			$updatedMin = date('Y-m-d\T00:00:00\Z', time() - $farLimit);
		}
		$抽出オプション
		= array(
			'singleEvents' => TRUE,
			'updatedMin' => $updatedMin,
			'orderBy' => 'startTime',
		);
		// Google_Service_Calendar_Events array of Google_Service_Calendar_Event
		$イベントリスト = $this->_カレンダーサービス->events->listEvents($this->_選択カレンダーＩＤ, $抽出オプション)->getItems();
		foreach ($イベントリスト as $イベント) {
			if ($イベント instanceof Google_Service_Calendar_Event) {
				$イベントID = $イベント->getId();
				if (empty($イベント->summary)) {
					continue;
				}
				$イベント名 = $イベント->getSummary();
				$スタート日時 = strtotime($イベント->getStart()->dateTime);//might UNIX TIME
				$終了日時 = strtotime($イベント->getEnd()->dateTime);//might UNIX TIME
				$終日フラグ = 1;
				if (!empty($イベント->getStart()->date)) {
					$終日フラグ = 0;
					$スタート日時 = strtotime($イベント->getStart()->date);
					$終了日時 = $スタート日時;
				}
				$説明 = $イベント->getDescription();
				$更新日 = $イベント->getUpdated();
				$result[] =
				array(
					self::KEY_EVENT_ID=>$イベントID,
					self::KEY_EVENT_NAME=>$イベント名,
					self::KEY_EVENT_START_TIME=>$スタート日時,
					self::KEY_EVENT_END_TIME=>$終了日時,
					self::KEY_EVENT_ALLDAY=>$終日フラグ,
					self::KEY_EVENT_CONTENT=>$説明,
					self::KEY_EVENT_UPDATED=>$更新日,
				);
			}
		}
		$this->_検索結果イベント数 = count($result);
		return $result;
	}

	public function カレンダー名を返す($index)
	{
		if ($index > $this->_カレンダーリスト->count()) {
			return FALSE;
		}
		$CalendarItems = $this->_カレンダーリスト->getItems();
		$CalendarName = $CalendarItems[$index]->summary;
		return $CalendarName;
	}
	public function _getUser($index){return $this->カレンダー名を返す($index);}

	/**
	 * プライマリカレンダーのインデックスを返す
	 * @return number
	 */
	public function プライマリカレンダーのインデックスを返す()
	{
		$index = 0;
		$CalendarItems = $this->_カレンダーリスト->getItems();
		foreach ($CalendarItems as $Item) {
			$Item instanceof Google_Service_Calendar_CalendarListEntry;
			if ($Item->primary === TRUE) {
				return $index;
			}
			$index ++;
		}
		return $index;
	}

	/**
	 * カレンダーのIDを返す
	 * @param  $index
	 * @return string | boolean
	 */
	public function カレンダーのIDを返す($index)
	{
		$id = '';
		if ($index > $this->_カレンダーリスト->count()) {
			return FALSE;
		}
		$CalendarItems = $this->_カレンダーリスト->getItems();
		$Item = $CalendarItems[$index];
		$Item instanceof Google_Service_Calendar_CalendarListEntry;
		$id = $Item->id;
		return $id;
	}

	public function 対象カレンダー名を指定する($name)
	{
		return $this->selectCalendarByName($name);
	}
	public function selectCalendarByName($name)
	{
		$CalendarItems = $this->_カレンダーリスト->getItems();
		$this->_選択カレンダーＩＤ = $CalendarItems[0]->id;
		foreach ($CalendarItems as $Item) {
			$Item instanceof Google_Service_Calendar_CalendarListEntry;
			if ($Item->summary == $name) {
				$this->_選択カレンダーＩＤ = $Item->id;
				return TRUE;
			}
		}
		return FALSE;
	}

	public function 対象カレンダー登録番号を指定する($index)
	{
		return $this->selectCalendarByIndex($index);
	}
	public function selectCalendarByIndex($index)
	{
		if ($index >= $this->getCalendarCount()) {
			return FALSE;
		}
		$CalendarItems = $this->_カレンダーリスト->getItems();
		$Item = $CalendarItems[$index];
		$Item instanceof Google_Service_Calendar_CalendarListEntry;
		$this->_選択カレンダーＩＤ = $Item->id;
		return TRUE;
	}
	const デフォルト期間 = 3600; // 一時間
	/**
	 * イベントを追加する
	 *
	 * @param unknown $title
	 * @param unknown $content
	 * @param unknown $startDateTime YYYY-MM-DD HH:SS
	 * @param unknown $endDateTime YYYY-MM-DD HH:SS
	 */
	public function イベントを追加する($title, $content, $startDateTime, $endDateTime = '') {
		$start = new Google_Service_Calendar_EventDateTime ();
		$end = new Google_Service_Calendar_EventDateTime ();
		$this->イベント開始終了日時を設定($start, $end, $startDateTime, $endDateTime);
		$newEvent = new Google_Service_Calendar_Event ();
		$newEvent->setSummary ( $title );
		$newEvent->setstart ( $start );
		$newEvent->setend ( $end );
		$newEvent->setDescription ( $content );
		$ret = $this->_カレンダーサービス->events->insert ( $this->_選択カレンダーＩＤ, $newEvent );
		$eventId = $ret->getId();
		return $eventId;
	}
	public function addEvent($title,$content,$startDateTime,	$endDateTime=''){return $this->イベントを追加する($title, $content, $startDateTime, $endDateTime);}

	/**
	 * 終日判定
	 * 指定日時フォーマットに時刻が設定されていない場合TRUEを返す
	 * @param unknown $startDateTime
	 * @return boolean
	 */
	protected function isAllday($startDateTime) {
		$divide = explode ( ' ', $startDateTime );
		if (count ( $divide ) == 1) {
			return TRUE;
		}
		return FALSE;
	}
	protected function イベント開始終了日時を設定(
			Google_Service_Calendar_EventDateTime $start,
			Google_Service_Calendar_EventDateTime $end,
			$startDateTime, $endDateTime
	){
		if ($endDateTime == '') {
			$dateTime = strtotime ( $startDateTime ) + self::デフォルト期間;
			$endDateTime = date ( 'Y-m-d H:i', $dateTime );
		}
		if ($this->isAllday ( $startDateTime )) {
			$start->setDate ( $startDateTime );
			$end->setdate ( $startDateTime );
		} else {
			$startDateTime = date('Y-m-d\TH:i:00+09:00', strtotime($startDateTime));
			$endDateTime = date('Y-m-d\TH:i:00+09:00', strtotime($endDateTime));
			$start->setDateTime ( $startDateTime );
			$end->setDateTime ( $endDateTime );
		}
	}

	protected $_対象イベント = FALSE;
	public function イベントを変更する(
			$title,
			$memo,
			$startDateTime,
			$endDateTime = ''
	){
		$start = new Google_Service_Calendar_EventDateTime();
		$end = new Google_Service_Calendar_EventDateTime();
		$this->イベント開始終了日時を設定($start, $end, $startDateTime, $endDateTime);
		$this->_対象イベント->setSummary($title);
		$this->_対象イベント->setDescription($memo);
		$this->_対象イベント->setStart($start);
		$this->_対象イベント->setEnd($end);
		$ret =$this->_カレンダーサービス->events->update($this->_選択カレンダーＩＤ, $this->_対象イベント->id, $this->_対象イベント);
		return $ret;
	}
	public function updateEvent($title,$memo,$startDateTime,$endDateTime = ''){return $this->イベントを変更する($title, $memo, $startDateTime, $endDateTime);}

	public function 編集イベントを設定する($eventId)
	{
		$this->_対象イベント = $this->イベントIDからイベントを取得する($eventId);
		return $this->_対象イベント;
	}
	public function setTargetEvent($eventId){return $this->編集イベントを設定する($eventId);}

	public function イベントIDからイベントを取得する($eventId){
		return $this->_カレンダーサービス->events->get($this->_選択カレンダーＩＤ, $eventId);
	}
	public function getEventFromId($eventId){return $this->イベントIDからイベントを取得する($eventId);}

	public function 更新ターゲットイベントを返す(){return $this->getTargetEvent();}
	/**
	 * 更新ターゲットイベントを返す
	 * @return boolean
	 */
	public function getTargetEvent()
	{
		return $this->_対象イベント;
	}

	public function 検索結果のイベント数を返す(){return $this->getEventCount();}
	public function getEventCount()
	{
		return $this->_検索結果イベント数;
	}
}

/*ユニットテストブロック V2*/
if (class_exists('ユニットテストケース')) {
	class ユニークな名前_test extends ユニットテストケース
	{
		protected $テストするクラス名='Calendar';
		const TOKEN = '{"access_token":"ya29.zQB4WsKkg9vx2UNeym8D-jAbjmT8RTamQGsIJDV788nCySM5c6XijOPMuLEgwCTYBBszx7n3t4kcBg","token_type":"Bearer","expires_in":3574,"created":1417298827}';
		//ここがテストケースの記載場所
		function test_カレンダーリスト取得()
		{
			Calendar::createCalendarClient(self::TOKEN, Calendar::TYPE_ACCESS_TOKEN);
			$obj = new Calendar();
			$カレンダー一覧 = $obj->getCalendarList();
		}
		function test_イベントリスト取得()
		{
			Calendar::createCalendarClient(self::TOKEN, Calendar::TYPE_ACCESS_TOKEN);
			$obj = new Calendar();
			$obj->対象カレンダー名を指定する('Toodledo');
			$ret = $obj->getEventList('2014-11-11T00:00:00Z');
			print_r($ret);
		}
		function test_カレンダー名でカレンダーを指定する()
		{
			Calendar::createCalendarClient(self::TOKEN, Calendar::TYPE_ACCESS_TOKEN);
			$obj = new Calendar();
			$obj->selectCalendarByName('Toodledo');
		}
		function test_イベントを登録する()
		{
			Calendar::createCalendarClient(self::TOKEN,Calendar::TYPE_ACCESS_TOKEN);
			$obj=new Calendar();
			$obj->対象カレンダー名を指定する('Toodledo');
			$obj->イベントを追加する('こんにちは', 'これからです', '2014-11-29 09:00');
		}
		function test_イベントを変更する()
		{
			Calendar::createCalendarClient(self::TOKEN,Calendar::TYPE_ACCESS_TOKEN);
			$obj=new Calendar();
			$obj->対象カレンダー名を指定する('Toodledo');
			$イベント = $obj->イベントを追加する('こんにちは', 'これからです', '2014-11-29 09:00');
			$イベントID= $イベント->getid();
			$obj->編集イベントを設定する($イベントID);
			$obj->イベントを変更する('今日はじゃない', 'これ彼でもない', '2014-11-30 09:00');
		}
		function test_カレンダー名を返す()
		{
			Calendar::createCalendarClient(self::TOKEN,Calendar::TYPE_ACCESS_TOKEN);
			$obj=new Calendar();
			$ret = $obj->カレンダー名を返す(0);
			echo $ret."\n";
		}
	}
}